package com.rs.game.npc;

import com.rs.cache.loaders.NPCDefinitions;
import com.rs.game.Animation;
import com.rs.game.Entity;
import com.rs.game.Graphics;
import com.rs.game.Hit;
import com.rs.game.World;
import com.rs.game.WorldTile;
import com.rs.game.Hit.HitLook;
import com.rs.game.player.Player;
import com.rs.game.tasks.WorldTask;
import com.rs.game.tasks.WorldTasksManager;
import com.rs.utils.Utils;
import com.rs.game.npc.NpcDefinition;
import com.rs.game.item.Item;
@SuppressWarnings("serial")
public class NPC extends Entity {

	private int id;
	private WorldTile respawnTile;
	private int internalId;
	private int[] bonuses; //0 stab, 1 slash, 2 crush,3 mage, 4 range, 5 stab def, blahblah till 9
	public boolean attacked = false;
	private boolean forceRandomWalk;
	
	public NPC(int id, WorldTile tile, int mapAreaNameHash, boolean canBeAttackFromOutOfArea) {
		this(id, tile, mapAreaNameHash, canBeAttackFromOutOfArea, false);
	}
	
	/*
	 * creates and adds npc
	 */
	public NPC(int id, WorldTile tile, int mapAreaNameHash, boolean canBeAttackFromOutOfArea, boolean spawned) {
		super(tile);
		this.id = id;
		this.respawnTile = new WorldTile(tile);
		setHitpoints(getMaxHitpoints());
		setDirection(getRespawnDirection());
		forceRandomWalk = forceRandomWalk(id);
		//npc is inited on creating instance
		initEntity();
		World.addNPC(this);
		World.updateEntityRegion(this);
		//npc is started on creating instance
		loadMapRegions();
	}
					

	@Override
	public void finish() {
		if(hasFinished()) {
			return;
		}
		setFinished(true);
		World.updateEntityRegion(this);
		World.removeNPC(this);
	}

	public NPCDefinitions getDefinitions() {
		return NPCDefinitions.getNPCDefinitions(id);
	}
	
	@Override
	public int getMaxHitpoints() {
		return new NpcDefinition(id).getMaxHitpoints();
	}
	
	public int getId() {
		return id;
	}

	@Override
	public void processEntity() {
		if(isDead())
			return;
		if(getFreezeDelay() < System.currentTimeMillis()) {
			if((forceRandomWalk || (getDefinitions().walkMask & 0x2) != 0) && Math.random() * 1000.0 < 100.0) {
				if(!(attacked)) {
					int moveX = (int) Math.round(Math.random() * 20.0 - 10.0);
					int moveY = (int) Math.round(Math.random() * 20.0 - 10.0);
					resetWalkSteps();
					addWalkSteps(respawnTile.getX()+moveX, respawnTile.getY()+moveY);
				}
			}
		}
	}
	private static boolean forceRandomWalk(int npcId) {
		switch(npcId) {
		default:
			return false;//return NPCDefinitions.getNPCDefinitions(npcId).name.equals("null");
		}
	}
	
	public int getRespawnDirection() {
		NPCDefinitions definitions = getDefinitions();
		if (definitions.anInt853 << 32 != 0 && definitions.respawnDirection > 0 && definitions.respawnDirection <= 8)
			return definitions.respawnDirection -1;
		return 0;
	}
	
	/*
	 * forces npc to random walk even if cache says no, used because of fake cache information
	 */

	public boolean isNextTo(final Entity player) {
		if(player.getX() + 1 == getX() && player.getY() == getY()
		 || player.getX() == getX() && player.getY() + 1 == getY()
		 || player.getX() + 1 == getX() && player.getY() + 1 == getY()
		 || player.getX() + 1 == getX() && player.getY() - 1 == getY()
		 || player.getX() == getX() && player.getY() - 1 == getY()
		 || player.getX() -1 == getX() && player.getY() - 1 == getY()
		 || player.getX() -1 == getX() && player.getY() == getY()
		 || player.getX() -1 == getX() && player.getY() + 1 == getY()) {
			return true;
		}
		return false;
	}

	public void moveToPlayer(final Entity player) {
		addWalkSteps(player.getX() + 1, player.getY());
	}		

	public void attack(final Player p, final Entity player) {
		System.out.println(id);
		moveToPlayer(player);
		setNextFaceEntity(player);
		//setNextFaceWorldTile(new WorldTile(player.getX(), player.getY(), 0));
		new Thread(new Runnable() {
			public void run() {
				try {
					while(!(player.isDead()) && !(isDead())) {
						if(!(isNextTo(player))) {
							moveToPlayer(player);
						}	
						Thread.sleep(new NpcDefinition(id).getSpeed() * 450);	
						setNextFaceEntity(player);
						//setNextFaceWorldTile(new WorldTile(player.getX(), player.getY(), 0));
						int distanceX = player.getX()- getX();
						int distanceY = player.getY()- getY();	
						if(distanceX == -1 || distanceX == 1 ||distanceX == 0) {
							if(distanceY == -1 || distanceY == 1 ||distanceY == 0) {
								if(!(player.isDead()) && ! (isDead())) {	
									setNextAnimation(new Animation(new NpcDefinition(id).getAttackAnim()));
									System.out.println(new NpcDefinition(id).getAttackAnim() + " " + new NpcDefinition(id).getDefenceAnim() + " " + new NpcDefinition(id).getSound());
									Hit hit = new Hit(player, (int) (Math.random() * new NpcDefinition(id).getMaxHit()), HitLook.Melee_Hit);
									player.applyHit(hit);
									p.getPackets().sendSound(511, 0);
									if(p.getEquipment().hasShield()) {
										p.setNextAnimation(new Animation(403));
										int off = Utils.getRandom(9);
										p.getPackets().sendSound(new NpcDefinition(id).getSound(), 0);
										p.getPackets().sendSound(2746 + off, 0);
									} else {
										p.setNextAnimation(new Animation(404));
									}
								}
							}
							if(!(isNextTo(player))) {
								moveToPlayer(player);
							}	
						}
						if(!(isNextTo(player))) {
							moveToPlayer(player);
						}

					}
				} catch(Exception e) {	}
			}
		}).start();
	}

	@Override
	public void handleIngoingHit(final Hit hit) {
		System.out.println();
		Entity source = hit.getSource();
		if(source == null || hit.getLook() == HitLook.Absorve_Hit || hit.getLook() == HitLook.Reflect_Hit)
			return;
		if(source instanceof Player) {
			final Player p2 = (Player) source;
			if(!(attacked)) {
				attacked = true;
				attack(p2, p2);
			}
			if(p2.getPrayer().hasPrayersOn()) {
				if(p2.getPrayer().usingPrayer(1, 18)) {
					final NPC target = this;
					if(hit.getDamage() > 0)
						World.sendProjectile(p2, this, 2263, 11, 11 ,20, 5, 0, 0);
					p2.heal(hit.getDamage()/5);
					p2.getSkills().drainPrayer(hit.getDamage()/50);
					WorldTasksManager.schedule(new WorldTask() {
						@Override
						public void run() {
							setNextGraphics(new Graphics(2264));
							if(hit.getDamage() > 0)
								World.sendProjectile(target, p2, 2263, 11, 11 ,20, 5, 0, 0);
						}
					}, 1);
				}
				if(hit.getDamage() == 0)
					return;
				if(!p2.getPrayer().isBoostedLeech()) {
					if(hit.getLook() == HitLook.Melee_Hit) {
						if(p2.getPrayer().usingPrayer(1, 19)) {
								p2.getPrayer().setBoostedLeech(true);
								return;
						}else if(p2.getPrayer().usingPrayer(1, 1)) { //sap att
							if(Utils.getRandom(4) == 0) {
								if(p2.getPrayer().reachedMax(0)) {
									p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your sap curse has no effect.", true);
								}else{
									p2.getPrayer().increaseLeechBonus(0);
									p2.getPackets().sendGameMessage("Your curse drains Attack from the enemy, boosting your Attack.", true);
								}
							p2.setNextAnimation(new Animation(12569));
							p2.setNextGraphics(new Graphics(2214));
							p2.getPrayer().setBoostedLeech(true);
							World.sendProjectile(p2, this, 2215, 35, 35 ,20, 5, 0, 0);
							WorldTasksManager.schedule(new WorldTask() {
								@Override
								public void run() {
									setNextGraphics(new Graphics(2216));
								}
							}, 1);
							return;
							}
						}else {
							if(p2.getPrayer().usingPrayer(1, 10)) {
								if(Utils.getRandom(7) == 0) {
									if(p2.getPrayer().reachedMax(3)) {
										p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your leech curse has no effect.", true);
									}else{
										p2.getPrayer().increaseLeechBonus(3);
										p2.getPackets().sendGameMessage("Your curse drains Attack from the enemy, boosting your Attack.", true);
									}
									p2.setNextAnimation(new Animation(12575));
									p2.getPrayer().setBoostedLeech(true);
									World.sendProjectile(p2, this, 2231, 35, 35 ,20, 5, 0, 0);
									WorldTasksManager.schedule(new WorldTask() {
										@Override
										public void run() {
											setNextGraphics(new Graphics(2232));
										}
									}, 1);
									return;
								}
							}
							if(p2.getPrayer().usingPrayer(1, 14)) {
								if(Utils.getRandom(7) == 0) {
									if(p2.getPrayer().reachedMax(7)) {
										p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your leech curse has no effect.", true);
									}else{
										p2.getPrayer().increaseLeechBonus(7);
										p2.getPackets().sendGameMessage("Your curse drains Strength from the enemy, boosting your Strength.", true);
									}
									p2.setNextAnimation(new Animation(12575));
									p2.getPrayer().setBoostedLeech(true);
									World.sendProjectile(p2, this, 2248, 35, 35 ,20, 5, 0, 0);
									WorldTasksManager.schedule(new WorldTask() {
										@Override
										public void run() {
											setNextGraphics(new Graphics(2250));
										}
									}, 1);
									return;
								}
							}
							
						}
						}
						if(hit.getLook() == HitLook.Range_Hit) {
							if(p2.getPrayer().usingPrayer(1, 2)) { //sap range
								if(Utils.getRandom(4) == 0) {
									if(p2.getPrayer().reachedMax(1)) {
										p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your sap curse has no effect.", true);
									}else{
										p2.getPrayer().increaseLeechBonus(1);
										p2.getPackets().sendGameMessage("Your curse drains Range from the enemy, boosting your Range.", true);
									}
								p2.setNextAnimation(new Animation(12569));
								p2.setNextGraphics(new Graphics(2217));
								p2.getPrayer().setBoostedLeech(true);
								World.sendProjectile(p2, this, 2218, 35, 35 ,20, 5, 0, 0);
								WorldTasksManager.schedule(new WorldTask() {
									@Override
									public void run() {
										setNextGraphics(new Graphics(2219));
									}
								}, 1);
								return;
								}
							}else if(p2.getPrayer().usingPrayer(1, 11)) {
								if(Utils.getRandom(7) == 0) {
									if(p2.getPrayer().reachedMax(4)) {
										p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your leech curse has no effect.", true);
									}else{
										p2.getPrayer().increaseLeechBonus(4);
										p2.getPackets().sendGameMessage("Your curse drains Range from the enemy, boosting your Range.", true);
									}
									p2.setNextAnimation(new Animation(12575));
									p2.getPrayer().setBoostedLeech(true);
									World.sendProjectile(p2, this, 2236, 35, 35 ,20, 5, 0, 0);
									WorldTasksManager.schedule(new WorldTask() {
										@Override
										public void run() {
											setNextGraphics(new Graphics(2238));
										}
									});
									return;
								}
							}
						}
						if(hit.getLook() == HitLook.Mage_Hit) {
							if(p2.getPrayer().usingPrayer(1, 3)) { //sap mage
								if(Utils.getRandom(4) == 0) {
								if(p2.getPrayer().reachedMax(2)) {
									p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your sap curse has no effect.", true);
								}else{
									p2.getPrayer().increaseLeechBonus(2);
									p2.getPackets().sendGameMessage("Your curse drains Magic from the enemy, boosting your Magic.", true);
								}
								p2.setNextAnimation(new Animation(12569));
								p2.setNextGraphics(new Graphics(2220));
								p2.getPrayer().setBoostedLeech(true);
								World.sendProjectile(p2, this, 2221, 35, 35 ,20, 5, 0, 0);
								WorldTasksManager.schedule(new WorldTask() {
									@Override
									public void run() {
										setNextGraphics(new Graphics(2222));
									}
								}, 1);
								return;
								}
							}else if(p2.getPrayer().usingPrayer(1, 12)) {
								if(Utils.getRandom(7) == 0) {
									if(p2.getPrayer().reachedMax(5)) {
										p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your leech curse has no effect.", true);
									}else{
										p2.getPrayer().increaseLeechBonus(5);
										p2.getPackets().sendGameMessage("Your curse drains Magic from the enemy, boosting your Magic.", true);
									}
									p2.setNextAnimation(new Animation(12575));
									p2.getPrayer().setBoostedLeech(true);
									World.sendProjectile(p2, this, 2240, 35, 35 ,20, 5, 0, 0);
									WorldTasksManager.schedule(new WorldTask() {
										@Override
										public void run() {
											setNextGraphics(new Graphics(2242));
										}
									}, 1);
									return;
								}
							}
						}
						
						//overall
						
						if(p2.getPrayer().usingPrayer(1, 13)) { //leech defence
							if(Utils.getRandom(10) == 0) {
								if(p2.getPrayer().reachedMax(6)) {
									p2.getPackets().sendGameMessage("Your opponent has been weakened so much that your leech curse has no effect.", true);
								}else{
									p2.getPrayer().increaseLeechBonus(6);
									p2.getPackets().sendGameMessage("Your curse drains Defence from the enemy, boosting your Defence.", true);
								}
								p2.setNextAnimation(new Animation(12575));
								p2.getPrayer().setBoostedLeech(true);
								World.sendProjectile(p2, this, 2244, 35, 35 ,20, 5, 0, 0);
								WorldTasksManager.schedule(new WorldTask() {
									@Override
									public void run() {
										setNextGraphics(new Graphics(2246));
									}
								}, 1);
								return;
							}
						}
				}
			}
		}
		
	}

	@Override
	public void sendDeath(Entity source) {
		setNextAnimation(new Animation(new NpcDefinition(id).getDeathAnim()));
		new Thread(new Runnable() {
			public void run() {
				try {
					Thread.sleep(3000);
					finish();
				} catch(Exception e) {	 }
			}
		}).start();
		
	}

	@Override
	public int getSize() {
		return getDefinitions().size;
	}
	
	public int getDefenceEmote() {
		return new NpcDefinition(id).getDefenceAnim();
	}
	
	
	public int getMaxHit() {
		return new NpcDefinition(id).getMaxHit();
	}

	public int[] getBonuses() {
		return bonuses;
	}

	@Override
	public double getMagePrayerMultiplier() {
		return 0;
	}

	@Override
	public double getRangePrayerMultiplier() {
		return 0;
	}

	@Override
	public double getMeleePrayerMultiplier() {
		return 0;
	}
	
	public WorldTile getRespawnTile() {
		return respawnTile;
	}
	
}
